package com.ishitong.platform.utils.hibernate;

import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.Configurable;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.util.PropertiesHelper;
import org.hibernate.dialect.Dialect;
import org.hibernate.type.Type;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.Serializable;
import java.util.Properties;

/**
 * 长整型ID发生器<br>
 * 
 */
public class LongIdGenerator implements IdentifierGenerator, Configurable {
	protected Log logger = LogFactory.getLog(getClass());

	private int digits; // 缺省值为3位

	private boolean regular; // 缺省为非正规表示方式

	LongSequence longSequence = new LongSequence();

	private long currentKey;// 当前key

	public LongIdGenerator() {
	}

	public synchronized Serializable generate(SessionImplementor session, Object object) throws HibernateException {
		long key = 0L;
		// 为序列号保留位数
		key = (Long) getKey();
		while (currentKey == key) {
			key = (Long) getKey();
			if (currentKey != key) {
				break;
			}
		}
		currentKey = key;
		return key;
	}

	private long getKey() {
		long key = getDate();
		// 为序列号保留位数
		long plus = (10 ^ digits);
		key = key * plus;
		long seq = longSequence.getNextId(1l);
		key = key + seq;
		return key;
	}

	public void configure(Type type, Properties params, Dialect d) throws MappingException {
		regular = PropertiesHelper.getBoolean("regular", params, false);
		digits = PropertiesHelper.getInt("digits", params, 3);
		if (regular) {
			// 如果是正规表示方式，最大长度不能超过5
			if (digits > 5) {
				logger.warn("主键使用正规表示方式时，序列号不能超过5位");
				digits = 5;
			}
		} else {
			// TODO：非正规表示方式需要确定最大位数
		}
		if (digits < 3) {
			logger.warn("主键使用的序列号最低3位");
			digits = 3;
		}
	}

	/**
	 * 取得整形表达的当前时间
	 * 
	 * @return 转化为长整形表示的当前系统时间
	 */
	private long getDate() {
		if (regular) {
			// TODO：正规表示方式
			return 0l;
		} else {
			// 长整形表示方式
			return System.currentTimeMillis();
		}
	}

}
